package com.lvideo.http;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.lvideo.http.bean.LVideoRequestHeader;
import com.lvideo.http.impl.LVideoHttpBaseParameter;
import com.lvideo.http.impl.LVideoHttpParameterCallback;

import org.apache.http.HttpStatus;
import org.apache.http.conn.ConnectTimeoutException;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.zip.GZIPInputStream;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * 网络请求处理类，java实现
 * */

public final class LVideoHttpJavaHandler implements LVideoHttpBaseHandler{

	/**
	 * GET 请求
	 * */
	public final String doGet(LVideoHttpBaseParameter<?,?,?> params) throws IOException {
		if(params == null){
			return null;
		}
		String baseUrl ;
		URL url;
		String response = null ;
		HttpURLConnection httpConnection = null;
		InputStream is = null ;

		try {
			baseUrl = params.getBaseUrl() + params.encodeUrl();
			LVideoHttpLog.Log("GET  " + baseUrl);
			url = new URL(baseUrl);
			httpConnection = (HttpURLConnection) url.openConnection();

			LVideoHttpParameterCallback callback = params.getCallback() ;
			if(callback != null){
				callback.proRequest(httpConnection);
			}

			httpConnection.setRequestMethod("GET");
			String referer = params.getmReferer();
	        if (!TextUtils.isEmpty(referer)) {
	                httpConnection.setRequestProperty(LVideoHttpConstant.REFERER, referer);
	        }

	        String useragent = params.getmUserAgent();
            if (!TextUtils.isEmpty(useragent)) {
                httpConnection.setRequestProperty(LVideoHttpConstant.USER_AGENT, useragent);
            }
			String contentType = params.getContentType();
			if (!TextUtils.isEmpty(contentType)) {
				httpConnection.setRequestProperty(LVideoHttpConstant.CONTENT_TYPE, contentType);
			}

			addRequestHead(httpConnection, params.getmHeader(), true);

			httpConnection.setReadTimeout(LVideoHttpConstant.READ_TIMEOUT);
			httpConnection.setConnectTimeout(LVideoHttpConstant.CONNECT_TIMEOUT);
			httpConnection.connect();
			int responseCode = httpConnection.getResponseCode();
			boolean isGzip = isGzip(httpConnection);
			if (responseCode == HttpStatus.SC_OK) {
				is = httpConnection.getInputStream();
			} else {
				if(LVideoHttpConstant.isDebug){
					is = httpConnection.getErrorStream();
					if (isGzip) {
						response = read(new GZIPInputStream(is));
					} else {
						response = read(is);
					}
					LVideoHttpLog.Err(response);
				}
				throw new IOException(responseCode +"");
			}
			if (isGzip) {
				response = read(new GZIPInputStream(is));
			} else {
				response = read(is);
			}
			LVideoHttpLog.Log(response);

			if(callback != null){
				callback.laterRequest(httpConnection);
			}

			return response ;
		}catch (ConnectTimeoutException timeoutException){
			throw new IOException(LVideoHttpConstant.TIMEOUT_CODE);	//timeout
		}catch (SocketTimeoutException socketTimeoutException){
			throw new IOException(LVideoHttpConstant.TIMEOUT_CODE);	//timeout
		}finally {
			httpConnection.disconnect();
			if(is != null){try {is.close();} catch (Exception e) {e.printStackTrace();}}
			url = null ;
			response = null ;
			httpConnection = null ;
			is = null ;
		}
	}




	/**
	 * POST 请求
	 * */
	public final String doPost(LVideoHttpBaseParameter<?,?,?> params) throws IOException {
		if(params == null){
			return null;
		}
		URL url;
		String response = null ;
		HttpURLConnection httpConnection = null;
		InputStream is = null ;

		LVideoHttpParameterCallback callback = params.getCallback() ;

		try {
			url = new URL(params.getBaseUrl() + params.encodeUrl());
			httpConnection = (HttpURLConnection) url.openConnection();

			if(callback != null){
				callback.proRequest(httpConnection);
			}

			String contentType = params.getContentType();
			if (!TextUtils.isEmpty(contentType)) {
				httpConnection.setRequestProperty(LVideoHttpConstant.CONTENT_TYPE, contentType);
			}

			addRequestHead(httpConnection, params.getmHeader(), true);

			httpConnection.setRequestMethod("POST");
			httpConnection.setReadTimeout(LVideoHttpConstant.READ_TIMEOUT);
			httpConnection.setConnectTimeout(LVideoHttpConstant.CONNECT_TIMEOUT);
			httpConnection.setDoOutput(true);
			httpConnection.connect();
//			String p = params.encodeUrl().toString() ;
//			LVideoHttpLog.Log("POST  " + params.getBaseUrl() + "?" + p);
//			httpConnection.getOutputStream().write(p.toString().getBytes());
			if(!TextUtils.isEmpty(params.getPostJsonData())){
				httpConnection.getOutputStream().write(params.getPostJsonData().getBytes());
			}

			int responseCode = httpConnection.getResponseCode();
			boolean isGzip = isGzip(httpConnection);
			if (responseCode == HttpStatus.SC_OK) {
				is = httpConnection.getInputStream();
			} else {
				if(LVideoHttpConstant.isDebug){
					is = httpConnection.getErrorStream();
					if (isGzip) {
						response = read(new GZIPInputStream(is));
					} else {
						response = read(is);
					}
					LVideoHttpLog.Err(response);
				}
				throw new IOException(responseCode +"");
			}

			if (isGzip) {
				response = read(new GZIPInputStream(is));
			} else {
				response = read(is);
			}
			LVideoHttpLog.Log(response);

			if(callback != null){
				callback.laterRequest(httpConnection);
			}

			return response ;
		}catch (ConnectTimeoutException timeoutException){
			throw new IOException(LVideoHttpConstant.TIMEOUT_CODE);	//timeout
		}catch (SocketTimeoutException socketTimeoutException){
			throw new IOException(LVideoHttpConstant.TIMEOUT_CODE);	//timeout
		} finally {
			httpConnection.disconnect();
			if(is != null){try {is.close();} catch (Exception e) {e.printStackTrace();}}
			url = null ;
			response = null ;
			httpConnection = null ;
			is = null ;
		}
	}

	/**
	 * GET 请求, https
	 * */
	public final String doHttpsGet(LVideoHttpBaseParameter<?,?,?> params, Context context) throws IOException {
		if(params == null){
			return null;
		}
		String baseUrl ;
		URL url;
		String response = null ;
		HttpsURLConnection httpsConnection = null;
		InputStream is = null ;

		try {
			baseUrl = params.getBaseUrl() + params.encodeUrl();
			LVideoHttpLog.Log("GET  " + baseUrl);
			url = new URL(baseUrl);
			SSLContext sc = SSLContext.getInstance("TLS");
			sc.init(TrustSSLSocketFactory.createKeyManagers(context), new TrustManager[]{new MyTrustManager()}, new SecureRandom());
			HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
			HttpsURLConnection.setDefaultHostnameVerifier(new MyHostnameVerifier());
			httpsConnection = (HttpsURLConnection) url.openConnection();

			LVideoHttpParameterCallback callback = params.getCallback() ;
			if(callback != null){
				callback.proRequest(httpsConnection);
			}

			httpsConnection.setRequestMethod("GET");
			String referer = params.getmReferer();
			if (!TextUtils.isEmpty(referer)) {
				httpsConnection.setRequestProperty(LVideoHttpConstant.REFERER, referer);
			}

			String useragent = params.getmUserAgent();
			if (!TextUtils.isEmpty(useragent)) {
				httpsConnection.setRequestProperty(LVideoHttpConstant.USER_AGENT, useragent);
			}
			String contentType = params.getContentType();
			if (!TextUtils.isEmpty(contentType)) {
				httpsConnection.setRequestProperty(LVideoHttpConstant.CONTENT_TYPE, contentType);
			}

			addRequestHead(httpsConnection, params.getmHeader(), true);

			httpsConnection.setReadTimeout(LVideoHttpConstant.READ_TIMEOUT);
			httpsConnection.setConnectTimeout(LVideoHttpConstant.CONNECT_TIMEOUT);
			httpsConnection.setDoOutput(false);
			httpsConnection.setDoInput(true);
			httpsConnection.connect();
			int responseCode = httpsConnection.getResponseCode();
			boolean isGzip = isGzip(httpsConnection);
			if (responseCode == HttpStatus.SC_OK) {
				is = httpsConnection.getInputStream();
			} else {
				if(LVideoHttpConstant.isDebug){
					is = httpsConnection.getErrorStream();
					if (isGzip) {
						response = read(new GZIPInputStream(is));
					} else {
						response = read(is);
					}
					LVideoHttpLog.Err(response);
				}
				throw new IOException(responseCode +"");
			}
			if (isGzip) {
				response = read(new GZIPInputStream(is));
			} else {
				response = read(is);
			}
			LVideoHttpLog.Log(response);

			if(callback != null){
				callback.laterRequest(httpsConnection);
			}

			return response ;
		}catch (ConnectTimeoutException timeoutException){
			throw new IOException(LVideoHttpConstant.TIMEOUT_CODE);	//timeout
		}catch (SocketTimeoutException socketTimeoutException){
			throw new IOException(LVideoHttpConstant.TIMEOUT_CODE);	//timeout
		}catch (Exception e){
			Log.e(this.getClass().getName(), e.getMessage());
			return  response;
		} finally {
			httpsConnection.disconnect();
			if(is != null){try {is.close();} catch (Exception e) {e.printStackTrace();}}
			url = null ;
			response = null ;
			httpsConnection = null ;
			is = null ;
		}
	}

	/**
	 * POST 请求,https
	 * */
	public final String doHttpsPost(LVideoHttpBaseParameter<?,?,?> params, Context context) throws IOException {
		if(params == null){
			return null;
		}
		URL url;
		String response = null ;
		HttpsURLConnection httpsConnection = null;
		InputStream is = null ;

		LVideoHttpParameterCallback callback = params.getCallback() ;

		try {
			url = new URL(params.getBaseUrl() + params.encodeUrl());
			SSLContext sc = SSLContext.getInstance("TLS");
			sc.init(TrustSSLSocketFactory.createKeyManagers(context), new TrustManager[]{new MyTrustManager()}, new SecureRandom());
			HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
			HttpsURLConnection.setDefaultHostnameVerifier(new MyHostnameVerifier());
			httpsConnection = (HttpsURLConnection) url.openConnection();

			if(callback != null){
				callback.proRequest(httpsConnection);
			}
			String contentType = params.getContentType();
			if (!TextUtils.isEmpty(contentType)) {
				httpsConnection.setRequestProperty(LVideoHttpConstant.CONTENT_TYPE, contentType);
			}

			addRequestHead(httpsConnection, params.getmHeader(), true);

			httpsConnection.setRequestMethod("POST");
			httpsConnection.setReadTimeout(LVideoHttpConstant.READ_TIMEOUT);
			httpsConnection.setConnectTimeout(LVideoHttpConstant.CONNECT_TIMEOUT);
			httpsConnection.setDoOutput(true);
			httpsConnection.setDoInput(true);
			httpsConnection.connect();
//			String p = params.encodeUrl().toString() ;
//			LVideoHttpLog.Log("POST  " + params.getBaseUrl() + "?" + p);
//			httpsConnection.getOutputStream().write(p.toString().getBytes());
			if(!TextUtils.isEmpty(params.getPostJsonData())){
				httpsConnection.getOutputStream().write(params.getPostJsonData().getBytes());
			}

			int responseCode = httpsConnection.getResponseCode();
			boolean isGzip = isGzip(httpsConnection);
			if (responseCode == HttpStatus.SC_OK) {
				is = httpsConnection.getInputStream();
			} else {
				if(LVideoHttpConstant.isDebug){
					is = httpsConnection.getErrorStream();
					if (isGzip) {
						response = read(new GZIPInputStream(is));
					} else {
						response = read(is);
					}
					LVideoHttpLog.Err(response);
				}
				throw new IOException(responseCode +"");
			}

			if (isGzip) {
				response = read(new GZIPInputStream(is));
			} else {
				response = read(is);
			}
			LVideoHttpLog.Log(response);

			if(callback != null){
				callback.laterRequest(httpsConnection);
			}

			return response ;
		}catch (ConnectTimeoutException timeoutException){
			throw new IOException(LVideoHttpConstant.TIMEOUT_CODE);	//timeout
		}catch (SocketTimeoutException socketTimeoutException){
			throw new IOException(LVideoHttpConstant.TIMEOUT_CODE);	//timeout
		} catch (Exception e){
			Log.e(this.getClass().getName(), e.getMessage());
			return  response;
		} finally {
			httpsConnection.disconnect();
			if(is != null){
				try {
					is.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			url = null ;
			response = null ;
			httpsConnection = null ;
			is = null ;
		}
	}


	private class MyHostnameVerifier implements HostnameVerifier{
		@Override
		public boolean verify(String s, SSLSession sslSession) {
			return true;
		}
	}

	private class MyTrustManager implements X509TrustManager{
		@Override
		public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
			//
		}

		@Override
		public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
			//
		}

		@Override
		public X509Certificate[] getAcceptedIssuers() {
//			return new X509Certificate[0];
			return null;
		}
	}
	
	/**
	 * 将回来的IO流转化为字符串
	 * */
	private final String read(InputStream in) throws IOException {
		if(in == null){
			return null ;
		}
		InputStreamReader r = null ;
		String result = null ;
		char[] buf = new char[100] ;
		try{
			StringBuilder sb = new StringBuilder();
			r = new InputStreamReader(in);
			int len = 0 ;
			while ((len = r.read(buf)) != -1) {
				sb.append(buf , 0 , len);
			}

			result = sb.toString();

			return result ;
		} finally{
			if(r != null){r.close();}
			r = null ;
			result = null ;
			buf = null ;
			in = null ;
		}
	}

	/**
	 *	为请求增加header头信息
	 * @param httpConnection
	 */
	public static void addRequestHead(HttpURLConnection httpConnection, LVideoRequestHeader header, boolean gzipEnable){
		if(header != null){
			httpConnection.addRequestProperty("k-token", header.getkToken());
			httpConnection.addRequestProperty("k-appid", header.getkAppid());
			httpConnection.addRequestProperty("k-market", header.getkMarket());
			httpConnection.addRequestProperty("k-version", header.getkVersion());
			httpConnection.addRequestProperty("k-terminal", header.getkTeminal());
			httpConnection.addRequestProperty("k-model", header.getkModel());
			httpConnection.addRequestProperty("k-screen", header.getkScreen());
			httpConnection.addRequestProperty("k-os", header.getkOS());
			httpConnection.addRequestProperty("k-sdk", header.getkSdk());
			httpConnection.addRequestProperty("k-uuid", header.getkUuid());
			httpConnection.addRequestProperty("k-uid", header.getkUid());
			httpConnection.addRequestProperty("k-dc", header.getkDc());
			httpConnection.addRequestProperty("k-auid", header.getkAuid());
			if (gzipEnable) {
				httpConnection.addRequestProperty(LVideoHttpConstant.ACCEPT_ENCODING, "gzip");
			}
		}
	}

	/**
	 *
	 * @param httpConnection
	 * @return
     */
	private boolean isGzip(URLConnection httpConnection) {
		if (httpConnection == null) {
			return false;
		}
		String contentCode = httpConnection.getContentEncoding();
		if (!TextUtils.isEmpty(contentCode) && contentCode.contains("gzip")) {
			return true;
		}
		return false;
	}
}
